﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HR.ProjectX.BLL.Messaging;
using HR.ProjectX.DAL.UnitOfWork;
using HR.ProjectX.DAL.Repositories;
using HR.ProjectX.BLL.ViewModels;
using HR.ProjectX.Models;
using HR.ProjectX.Models.Entities.Vehicles;

namespace HR.ProjectX.BLL.Services.VehicleService
{
    public class VehicleService : IVehicleService
    {
        private readonly IUnitOfWork _uow;
        private readonly IVehicleRepository _vehicleRepository;
        private readonly IVehicleCategoryRepository _vehicleCategoryRepository;
        private readonly IManufacturerRepository _manufacturerRepository;

        public VehicleService(IUnitOfWork uow,
                              IVehicleRepository vehicleRepository,
                              IVehicleCategoryRepository vehicleCategoryRepository,
                              IManufacturerRepository manufacturerRepository)
        {
            _uow = uow;
            _vehicleRepository = vehicleRepository;
            _vehicleCategoryRepository = vehicleCategoryRepository;
            _manufacturerRepository = manufacturerRepository;
        }

        public GetAllVehiclesResponse GetAllVehicles()
        {
            IList<Vehicle> vehicles = _vehicleRepository.FindAll();
            IList<VehicleView> viewModels = new List<VehicleView>();

            // Ik doe de mapping zelf ipv Automapper.
            foreach (Vehicle vehicle in vehicles)
            {
                VehicleView viewModel = new VehicleView();
                viewModel.Manufacturer = new ManufacturerView();
                viewModel.Model = new ModelView();
                viewModel.VehicleCategory = new VehicleCategoryView();

                viewModel.Manufacturer.ManufacturerName = vehicle.Manufacturer.ManufacturerName;
                viewModel.Manufacturer.ManufacturerDetails = vehicle.Manufacturer.ManufacturerDetails;

                viewModel.Model.ModelName = vehicle.Model.ModelName;

                viewModel.VehicleCategory.VehicleDescription = vehicle.VehicleCategory.VehicleCategoryDescription;

                viewModel.RegistrationNumber = vehicle.RegistrationNumber;
                viewModel.CurrentKilometers = vehicle.CurrentKilometers;
                viewModel.DailyHireRate = vehicle.DailyHireRate;

                viewModels.Add(viewModel);
            }

            GetAllVehiclesResponse response = new GetAllVehiclesResponse();
            response.Vehicles = viewModels;

            return response;
        }

        public GetAllVehiclesByResponse GetAllVehiclesByCategory(GetAllVehiclesByRequest request)
        {
            IList<Vehicle> vehicles = _vehicleRepository.FindAllVehiclesByCategory(request.VehicleCategory);
            IList<VehicleView> viewModels = new List<VehicleView>();

            // Ik doe de mapping zelf ipv Automapper.
            foreach (Vehicle vehicle in vehicles)
            {
                VehicleView viewModel = new VehicleView();
                viewModel.Manufacturer = new ManufacturerView();
                viewModel.Model = new ModelView();
                viewModel.VehicleCategory = new VehicleCategoryView();

                viewModel.Manufacturer.ManufacturerName = vehicle.Manufacturer.ManufacturerName;
                viewModel.Manufacturer.ManufacturerDetails = vehicle.Manufacturer.ManufacturerDetails;

                viewModel.Model.ModelName = vehicle.Model.ModelName;

                viewModel.VehicleCategory.VehicleDescription = vehicle.VehicleCategory.VehicleCategoryDescription;

                viewModel.RegistrationNumber = vehicle.RegistrationNumber;
                viewModel.CurrentKilometers = vehicle.CurrentKilometers;
                viewModel.DailyHireRate = vehicle.DailyHireRate;

                viewModels.Add(viewModel);
            }

            GetAllVehiclesByResponse response = new GetAllVehiclesByResponse();
            response.Vehicles = viewModels;

            return response;
        }

        public GetVehicleByResponse GetVehicleByModel(GetVehicleByRequest request)
        {
            Vehicle vehicle = _vehicleRepository.FindVehicleByModel(request.Model);
            VehicleView viewModel = new VehicleView();
            viewModel.Manufacturer = new ManufacturerView();
            viewModel.Model = new ModelView();
            viewModel.VehicleCategory = new VehicleCategoryView();

            viewModel.Manufacturer.ManufacturerName = vehicle.Manufacturer.ManufacturerName;
            viewModel.Manufacturer.ManufacturerDetails = vehicle.Manufacturer.ManufacturerDetails;
            viewModel.Model.ModelName = vehicle.Model.ModelName;
            viewModel.VehicleCategory.VehicleDescription = vehicle.VehicleCategory.VehicleCategoryDescription;

            viewModel.RegistrationNumber = vehicle.RegistrationNumber;
            viewModel.CurrentKilometers = vehicle.CurrentKilometers;
            viewModel.DailyHireRate = vehicle.DailyHireRate;

            GetVehicleByResponse response = new GetVehicleByResponse();
            response.Vehicle = viewModel;

            return response;
        }

        public void CreateVehicle(CreateVehicleRequest request)
        {
            Vehicle vehicle = new Vehicle();

            Manufacturer manufacturer = _manufacturerRepository.FindManufacturerByName(request.Manufacturer);
            VehicleCategory category = _vehicleCategoryRepository.FindVehicleCategoryByDescription(request.VehicleCategory);

            Model model = new Model();
            model.ModelName = request.Model;

            vehicle.Manufacturer = manufacturer;
            vehicle.Model = model;
            vehicle.VehicleCategory = category;
            vehicle.RegistrationNumber = request.RegistrationNumber;
            vehicle.CurrentKilometers = request.CurrentKilometers;
            vehicle.DailyHireRate = request.DailyHireRate;

            ThrowExceptionIfVehicleIsInvalid(vehicle);

            _vehicleRepository.Add(vehicle);
            _uow.Commit();
        }

        private void ThrowExceptionIfVehicleIsInvalid(Vehicle vehicle)
        {
            if (vehicle.GetBrokenRules().Count() > 0)
            {
                StringBuilder brokenRules = new StringBuilder();
                brokenRules.AppendLine("There were problems saving the Booking:");
                foreach (BusinessRule businessRule in vehicle.GetBrokenRules())
                {
                    brokenRules.AppendLine(businessRule.Rule);
                }

                throw new VehicleInvalidException(brokenRules.ToString());
            }
        }
    }
}
